package medico.manager;

import geral.manager.GenericManager;
import geral.manager.UtilManager;
import geral.util.FacesUtil;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.EJB;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.inject.Named;

import org.primefaces.event.SelectEvent;

import aspecto.annotation.Permissao;
import br.com.sgc.entities.cep.Cidade;
import br.com.sgc.entities.cep.UF;
import br.com.sgc.entities.geral.Agendamento;
import br.com.sgc.entities.geral.DiaSemana;
import br.com.sgc.entities.geral.Endereco;
import br.com.sgc.entities.geral.Exame;
import br.com.sgc.entities.geral.ExamePaciente;
import br.com.sgc.entities.geral.FichaPaciente;
import br.com.sgc.entities.geral.Paciente;
import br.com.sgc.entities.geral.PacienteAnimal;
import br.com.sgc.entities.geral.PacientePessoa;
import br.com.sgc.entities.geral.Telefone;
import br.com.sgc.entities.medico.Especialidade;
import br.com.sgc.entities.medico.EspecialidadeMedico;
import br.com.sgc.entities.medico.Medico;
import br.com.sgc.entities.medico.PlanoSaude;
import br.com.sgc.enuns.StatusAgendamento;
import br.com.sgc.exception.ValidacaoException;
import br.com.sgc.permissao.Role;
import br.com.sgc.session.AgendamentoSession;
import br.com.sgc.session.EspecialidadeMedicoSession;
import br.com.sgc.session.FichaPacienteSession;
import br.com.sgc.session.GenericSession;
import br.com.sgc.session.MedicoSession;
import br.com.sgc.session.PacienteAnimalSession;
import br.com.sgc.session.PacientePessoaSession;

@Named
@ConversationScoped
public class MedicoManager extends GenericManager implements Serializable {

	private static final long serialVersionUID = 1364584874360105825L;
	
	@EJB private MedicoSession medicoSession;
	
	@EJB private GenericSession<PlanoSaude> planoSaudeSession;
	
	@EJB private GenericSession<Especialidade> especialidadeSession;
	
	@EJB private GenericSession<Exame> exameSession;
	
	@EJB private GenericSession<Paciente> pacienteSession;
	
	@EJB private EspecialidadeMedicoSession emSession;
	
	@EJB private AgendamentoSession agendamentoSession;
	
	@EJB private FichaPacienteSession fichaPacienteSession;
	
	@EJB private PacienteAnimalSession pacienteAnimalSession;
	
	@EJB private PacientePessoaSession pacientePessoaSession;
	
	@Inject private UtilManager utilManager;

	private Medico medico = new Medico();
	
	private List<Medico> medicos = new ArrayList<Medico>();

	private EspecialidadeMedico especialidadeMedico = new EspecialidadeMedico();
	
	private List<Especialidade> listEspecialidade = new ArrayList<Especialidade>();
	
	private PlanoSaude planoSaude = new PlanoSaude();
	
	private List<PlanoSaude> listPlanoSaude = new ArrayList<PlanoSaude>();
	
	private Boolean isCpfValido;
	
	private Boolean showPanelCadastro;
	
	private List<Agendamento> listAgendamento = new ArrayList<Agendamento>();
	
	private Agendamento agendamento = new Agendamento();
	
	private Paciente paciente = new Paciente();
	
	private List<FichaPaciente> fichasPaciente = new ArrayList<FichaPaciente>();
	
	private List<Integer> listDiasSemana = new ArrayList<Integer>();
	
	private Date dataAgenda = new Date();
	
	private FichaPaciente fichaPaciente;
	
	private Boolean renderPanelPaciente = false;

	private Exame exame = new Exame();
	
	private List<Exame> listExame = new ArrayList<Exame>();
	
	
	
	@Permissao(role = Role.Sistema_SGC_Medico_Salvar)
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public String prepareSave(){
		clear();
		listPlanoSaude = planoSaudeSession.findAll(PlanoSaude.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
		listEspecialidade = especialidadeSession.findAll(Especialidade.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
		utilManager.getFuncionarioManager().prepareSave();
		showPanelCadastro = true;
		medico.setClinica(utilManager.getSegurancaManager().getUsuarioLogado().getClinica());
		return "formMedico";
	}
	

	@Permissao(role = Role.Sistema_SGC_Medico_Salvar)
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public String save() {
		try {
			medicoSession.fillMedico(medico, utilManager.getEnderecoManager().getListEndereco(), utilManager.getTelefoneManager().getListTelefone(), utilManager.getSegurancaManager().getUsuarioLogado().getClinica(),medico.getUsuario().getPerfilUsuario(),listDiasSemana);
			medicoSession.save(medico);
			FacesUtil.mensInfo("Salvo com Sucesso!!!");
			return list();
		} catch (ValidacaoException e) {
			e.printStackTrace();
			FacesUtil.mensWarn(e.getMessage());
		}
		return null;
	}
	


	@Permissao(role = Role.Sistema_SGC_Medico_Atualizar)
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public String update() {
		try {
			medicoSession.fillMedico(medico, utilManager.getEnderecoManager().getListEndereco(), utilManager.getTelefoneManager().getListTelefone(), medico.getClinica(),medico.getUsuario().getPerfilUsuario(),listDiasSemana);
			medicoSession.update(medico);
			FacesUtil.mensInfo("Atualizado com Sucesso!!!");
			return list();
		} catch (ValidacaoException e) {
			e.printStackTrace();
			FacesUtil.mensWarn(e.getMessage());
		}
		return null;
	}
	
	@Permissao(role = Role.Sistema_SGC_Medico_Listar)
	public String list() {
		medicos = medicoSession.findAll(Medico.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
		utilManager.getEnderecoManager().setRenderPanelCadastro(false);
		utilManager.getTelefoneManager().setRenderPanelCadastro(false);
		utilManager.getFuncionarioManager().prepareSave();
		showPanelCadastro = false;
		return "formMedico";
	}

	@Permissao(role = Role.Sistema_SGC_Medico_Atualizar)
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public String prepareUpdate(){
		utilManager.getEnderecoManager().setRenderPanelCadastro(true);
		utilManager.getTelefoneManager().setRenderPanelCadastro(true);
		
		medico = medicoSession.findById(Medico.class, medico.getId(), true);
		
		utilManager.getEnderecoManager().getListEndereco().clear();
		utilManager.getTelefoneManager().getListTelefone().clear();
		
		medico.setEnderecos(utilManager.getEnderecoManager().getEnderecoSession().getEnderecosPersistent(medico.getEnderecos()));
		medico.setTelefones(utilManager.getTelefoneManager().getTelefoneSession().getTelefonesPersistent(medico.getTelefones()));
		
		utilManager.getEnderecoManager().getListEndereco().addAll(medico.getEnderecos());
		utilManager.getTelefoneManager().getListTelefone().addAll(medico.getTelefones());
		
		medico.setEspecialidades(emSession.findEspecialidadesByMedico(medico));
		listEspecialidade = especialidadeSession.findAll(Especialidade.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
		listPlanoSaude = planoSaudeSession.findAll(PlanoSaude.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
		
		utilManager.getFuncionarioManager().getFuncionario().setId(medico.getId());
		utilManager.getFuncionarioManager().prepareUpdate();
		medico.setUsuario(utilManager.getFuncionarioManager().getFuncionario().getUsuario());
		
		getDiasSemanaFromMedico();
		
		showPanelCadastro = true;
		isCpfValido = true;
		return "formMedico";
	}
	
	private void getDiasSemanaFromMedico() {
		for(DiaSemana dias: medico.getDiasAtendimento()){
			listDiasSemana.add(dias.getDiaSemana());
		}
	}


	@Permissao(role = Role.Sistema_SGC_Medico_Excluir)
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public String delete(){
		try {
			medicoSession.delete(medico);
			FacesUtil.mensInfo("Exclu�do com Sucesso!!!");
		} catch (ValidacaoException e) {
			FacesUtil.mensInfo("Imposs�vel Excluir");
		}
		
		return list();
	}
	
	public void addPlanoSaude(){
		medico.getPlanosSaude().add(planoSaudeSession.findById(PlanoSaude.class, planoSaude.getId(), false));
		planoSaude = new PlanoSaude();
	}
	
	public void removePlanoSaude(){
		medico.getPlanosSaude().remove(planoSaude);
		planoSaude = new PlanoSaude();
	}
	
	public void addEspecialidade(){
		especialidadeMedico.setEspecialidade(especialidadeSession.findById(Especialidade.class, especialidadeMedico.getEspecialidade().getId()));
		especialidadeMedico.setMedico(medico);
		medico.getEspecialidades().add(especialidadeMedico);
		especialidadeMedico = new EspecialidadeMedico();
	}
	
	public void removeEspecialidade(){
		medico.getEspecialidades().remove(especialidadeMedico);
		especialidadeMedico = new EspecialidadeMedico();
	}
	
	public void validateCpf() {
		try {
			isCpfValido = false;
			medicoSession.validarCPF(medico.getCpf());
			medico = medicoSession.findByCPF(medico.getCpf(), utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
			
			utilManager.getEnderecoManager().setRenderPanelLogradouro(false);
			utilManager.getEnderecoManager().setListCidade(new ArrayList<Cidade>());
			utilManager.getEnderecoManager().setListUF(new ArrayList<UF>());
			utilManager.getEnderecoManager().setRenderPanelCadastro(true);
			utilManager.getTelefoneManager().setRenderPanelCadastro(true);
			
			utilManager.getTelefoneManager().getListTelefone().clear();
			utilManager.getTelefoneManager().setTelefone(new Telefone());
			
			utilManager.getEnderecoManager().setEndereco(new Endereco());
			utilManager.getEnderecoManager().getListEndereco().clear();
			
			utilManager.getEnderecoManager().setListEndereco(medico.getEnderecos());
			utilManager.getTelefoneManager().setListTelefone(medico.getTelefones());
			
			isCpfValido = true;

		} catch (ValidacaoException e) {
			FacesUtil.mensWarn(e.getMessage());
		}
	}
	
	public void clear(){
		utilManager.getEnderecoManager().setRenderPanelLogradouro(false);
		utilManager.getEnderecoManager().setListCidade(new ArrayList<Cidade>());
		utilManager.getEnderecoManager().setListUF(new ArrayList<UF>());
		utilManager.getEnderecoManager().setRenderPanelCadastro(true);
		utilManager.getTelefoneManager().setRenderPanelCadastro(true);
		
		utilManager.getTelefoneManager().getListTelefone().clear();
		utilManager.getTelefoneManager().setTelefone(new Telefone());
		
		utilManager.getEnderecoManager().setEndereco(new Endereco());
		utilManager.getEnderecoManager().getListEndereco().clear();
		
		medico = new Medico();
		medico.setAtivo(true);
		isCpfValido = false;
	}
	
	public String atenderConsulta() {
        agendamento = agendamentoSession.findById(Agendamento.class, agendamento.getId(), true);
        agendamento.setPaciente(pacienteSession.findById(Paciente.class, agendamento.getPaciente().getId(), true));
        fichasPaciente = fichaPacienteSession.findAllFichasByPaciente(agendamento.getPaciente());
        String retorno = null;
        if(agendamento.getPaciente() instanceof PacientePessoa){
        	fillPaciente();
        	retorno = "atenderConsulta";
        } else {
        	fillAnimal();
        	retorno = "atenderConsultaAnimal";
        }
        
        fillAgendamento();
        return retorno;
    }
	
	private void fillAnimal() {
		utilManager.getAnimalManager().setAnimal(((PacienteAnimal)agendamento.getPaciente()).getAnimal());
		utilManager.getAnimalManager().prepareUpdate();
		utilManager.getAnimalManager().setDisableInputs(true);
		
	}


	private void fillPaciente() {
		utilManager.getPacientePessoaManager().setPaciente((PacientePessoa)agendamento.getPaciente());
        utilManager.getPacientePessoaManager().prepareUpdate();
        fillAgendamento();
	}


	private void fillAgendamento() {
		fichaPaciente = new FichaPaciente();
	    fichaPaciente.setDataAtendimento(agendamento.getDataAgendamento());
        utilManager.getEnderecoManager().setRenderPanelCadastro(false);
        utilManager.getTelefoneManager().setRenderPanelCadastro(false);
        utilManager.getPacientePessoaManager().setIsTelaAtendimento(true);
	}


	public void prepareUpdateFichaPaciente(){
		fichaPaciente = fichaPacienteSession.findById(FichaPaciente.class, fichaPaciente.getId(), true);
		renderPanelPaciente = false;
		listExame = exameSession.findAll(Exame.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
	}
	
	public void updateFichaPaciente(){
		try {
			fichaPaciente.setPaciente(pacienteSession.findById(Paciente.class, fichaPaciente.getPaciente().getId()));
			fichaPacienteSession.update(fichaPaciente);
			atenderConsulta();
			FacesUtil.mensInfo("Prontuário Atualizada Com Sucesso.");
		} catch (ValidacaoException e) {
			FacesUtil.mensErro(e.getMessage());
		}
	}
	
	public void abrirNovaFicha(){
		try {
			exame = new Exame();
			agendamentoSession.validarAgendamento(agendamento);
			fichaPaciente = new FichaPaciente();
			fichaPaciente.setDataAtendimento(agendamento.getDataAgendamento());
			if(agendamento.getPaciente() != null)
				fichaPaciente.setPaciente(agendamento.getPaciente());

			listExame = exameSession.findAll(Exame.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
			
		} catch (Exception e) {
			FacesUtil.mensErro(e.getMessage());
		}
		
		
	}
	
	public void saveFichaPaciente(){
		try {
			fichaPaciente.setAgendamento(agendamento);
			fichaPaciente.setPaciente(pacienteSession.findById(Paciente.class, fichaPaciente.getPaciente(). getId()));
			fichaPacienteSession.save(fichaPaciente);
			agendamento.setStatusAgendamento(StatusAgendamento.EM_ATENDIMENTO);
			agendamentoSession.update(agendamento);
			atenderConsulta();
			FacesUtil.mensInfo("Prontuário Salvo Com Sucesso.");
		} catch (ValidacaoException e) {
			FacesUtil.mensErro(e.getMessage());
		}
		
		
	}
	
	public String concluirAtendimento(){
		try {
			agendamento.setStatusAgendamento(StatusAgendamento.CONCLUIDO);
			agendamentoSession.update(agendamento);
			showVisualizacaoMedico();
			FacesUtil.mensInfo("Consulta Finalizada");
		} catch (Exception e) {
			FacesUtil.mensErro(e.getMessage());
		}
		
		return "homeSGC";
	}
	
	public void printReceita(){
//		fichaPaciente = fichaPacienteSession.findById(FichaPaciente.class, fichaPaciente.getId(), true);
//		fichaPaciente.setPaciente(pacienteSession.findById(Paciente.class, fichaPaciente.getPaciente().getId()));
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("id", fichaPaciente.getReceituario().getId());
		map.put("nomeMedico", fichaPaciente.getAgendamento().getMedico().getNome());
		map.put("paciente", fichaPaciente.getPaciente().getDisplayNome());
		List<FichaPaciente> list = new ArrayList<FichaPaciente>();
		list.add(fichaPaciente);
		utilManager.getRelatorioManager().geraRelatorio(list, "receita.jasper", map, "receita.pdf");
	}
	
	public void showVisualizacaoMedico() {
		listAgendamento = agendamentoSession.findAllByMedicoDia(medico, dataAgenda);
		for(Agendamento a: listAgendamento){
			a.setPaciente(pacienteSession.findById(Paciente.class, a.getPaciente().getId()));
			if(a.getPaciente() instanceof PacienteAnimal){
				a.setPaciente(pacienteAnimalSession.findById(PacienteAnimal.class, a.getPaciente().getId(), true));
			} else {
				a.setPaciente(pacientePessoaSession.findById(PacientePessoa.class, a.getPaciente().getId(), true));
			}
		}
	}
	
	public void showVisualizacaoMedicoByDate(SelectEvent date) {
		dataAgenda = (Date)date.getObject();
		listAgendamento = agendamentoSession.findAllByMedicoDia(medico, dataAgenda);
	}
	
	public void prepareUpdatePaciente(){
		utilManager.getPacientePessoaManager().prepareUpdate();
		renderPanelPaciente = true;
	}
	
	public void updatePaciente(){
		utilManager.getPacientePessoaManager().update();
		renderPanelPaciente = false;
	}

	public Boolean podeAbrirFicha(){
		SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
		return sdf.format(this.agendamento.getDataAgendamento().getTime()).equals(sdf.format(new Date())) && (agendamento.getStatusAgendamento().equals(StatusAgendamento.AGENDADO) || agendamento.getStatusAgendamento().equals(StatusAgendamento.CONFIRMADO));
	}
	
	public Boolean podeReabrirFicha(Agendamento agendamento){
		SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
		return sdf.format(this.agendamento.getDataAgendamento().getTime()).equals(sdf.format(new Date())) && 
				agendamento != null && 
				this.agendamento.getId().equals(agendamento.getId()) && !this.agendamento.getStatusAgendamento().equals(StatusAgendamento.EM_ATENDIMENTO);
	}
	
	public void reabrirProntuario(){
		try {
			exame = new Exame();
			listExame = exameSession.findAll(Exame.class, utilManager.getSegurancaManager().getUsuarioLogado().getClinica().getId());
			fichaPaciente.getAgendamento().setStatusAgendamento(StatusAgendamento.EM_ATENDIMENTO);
			fichaPacienteSession.update(fichaPaciente, false);
			agendamento = agendamentoSession.update(fichaPaciente.getAgendamento());
			if(fichaPaciente.getExamesPaciente() == null){
				fichaPaciente.setExamesPaciente(new ArrayList<ExamePaciente>());
			}
		} catch (ValidacaoException e) {
			e.printStackTrace();
		}

	}

	public void addExame(){
		if(exame.getId() != null){
			ExamePaciente ex = new ExamePaciente();
			ex.setExame(exameSession.findById(Exame.class, exame.getId()));
			ex.setFicha(fichaPaciente);
			fichaPaciente.getExamesPaciente().add(ex);
			exame = new Exame();
		}
	}
	

	public Medico getMedico() {
		return medico;
	}

	public void setMedico(Medico medico) {
		this.medico = medico;
	}

	public List<Medico> getMedicos() {
		return medicos;
	}

	public void setMedicos(List<Medico> medicos) {
		this.medicos = medicos;
	}

	public List<PlanoSaude> getListPlanoSaude() {
		return listPlanoSaude;
	}

	public void setListPlanoSaude(List<PlanoSaude> listPlanoSaude) {
		this.listPlanoSaude = listPlanoSaude;
	}

	public Boolean getIsCpfValido() {
		return isCpfValido;
	}

	public void setIsCpfValido(Boolean isCpfValido) {
		this.isCpfValido = isCpfValido;
	}

	public PlanoSaude getPlanoSaude() {
		return planoSaude;
	}

	public void setPlanoSaude(PlanoSaude planoSaude) {
		this.planoSaude = planoSaude;
	}

	public EspecialidadeMedico getEspecialidadeMedico() {
		return especialidadeMedico;
	}

	public void setEspecialidadeMedico(EspecialidadeMedico especialidadeMedico) {
		this.especialidadeMedico = especialidadeMedico;
	}

	public List<Especialidade> getListEspecialidade() {
		return listEspecialidade;
	}

	public void setListEspecialidade(List<Especialidade> listEspecialidade) {
		this.listEspecialidade = listEspecialidade;
	}

	public Boolean getShowPanelCadastro() {
		return showPanelCadastro;
	}

	public void setShowPanelCadastro(Boolean showPanelCadastro) {
		this.showPanelCadastro = showPanelCadastro;
	}


	public List<FichaPaciente> getFichasPaciente() {
		return fichasPaciente;
	}


	public void setFichasPaciente(List<FichaPaciente> fichasPaciente) {
		this.fichasPaciente = fichasPaciente;
	}


	public Paciente getPaciente() {
		return paciente;
	}


	public void setPaciente(Paciente paciente) {
		this.paciente = paciente;
	}


	public Agendamento getAgendamento() {
		return agendamento;
	}


	public void setAgendamento(Agendamento agendamento) {
		this.agendamento = agendamento;
	}


	public FichaPaciente getFichaPaciente() {
		return fichaPaciente;
	}


	public void setFichaPaciente(FichaPaciente fichaPaciente) {
		this.fichaPaciente = fichaPaciente;
	}


	public List<Integer> getListDiasSemana() {
		return listDiasSemana;
	}


	public void setListDiasSemana(List<Integer> listDiasSemana) {
		this.listDiasSemana = listDiasSemana;
	}


	public List<Agendamento> getListAgendamento() {
		return listAgendamento;
	}


	public void setListAgendamento(List<Agendamento> listAgendamento) {
		this.listAgendamento = listAgendamento;
	}


	public Date getDataAgenda() {
		return dataAgenda;
	}


	public void setDataAgenda(Date dataAgenda) {
		this.dataAgenda = dataAgenda;
	}


	public Boolean getRenderPanelPaciente() {
		return renderPanelPaciente;
	}


	public void setRenderPanelPaciente(Boolean renderPanelPaciente) {
		this.renderPanelPaciente = renderPanelPaciente;
	}


	public MedicoSession getMedicoSession() {
		return medicoSession;
	}


	public void setMedicoSession(MedicoSession medicoSession) {
		this.medicoSession = medicoSession;
	}


	public List<Exame> getListExame() {
		return listExame;
	}


	public void setListExame(List<Exame> listExame) {
		this.listExame = listExame;
	}


	public Exame getExame() {
		return exame;
	}


	public void setExame(Exame exame) {
		this.exame = exame;
	}
	
}
